/**
 * 
 */
package com.netscenery.yang.model;

import java.util.ArrayList;

import com.netscenery.util.ErrTag;
import com.netscenery.util.Field;
import com.netscenery.yang.designer.LeafFieldMap;
import com.netscenery.yang.designer.ListFieldMap;
import com.netscenery.yang.designer.MapInfo;
import com.netscenery.yang.designer.MethodInfo;
import com.netscenery.yang.designer.Parameter;


/**
 * @author llly
 *
 */
public class YangList extends Node {
	private Field key;
	//private String keysEx;
	private ArrayList<Unique> uniques;
	//private String uniquesEx;
	private int minElements;
	private int maxElements;
	private boolean useDefaultMinElements = true;
	private boolean useDefaultMaxElements = true;
	public enum OrderBy{
		SYSTEM,
		USER
	}

	private OrderBy orderBy;


	
	
	public YangList(Env env, String name) throws ModelException{
		super(env,name);
	}
	
	
	/**
	 * @return the orderBy
	 */
	public OrderBy getOrderBy() {
		return orderBy;
	}


	/**
	 * @param orderBy the orderBy to set
	 */
	public void setOrderBy(OrderBy orderBy) {
		this.orderBy = orderBy;
	}


	public boolean isMandatory(){
		if (true == useDefaultMinElements){
			return false;
		}
		if (minElements > 0){
			return true;
		}
		
		return false;
	}
	
	/**
	 * @return the useDefaultMinElements
	 */
	public boolean isUseDefaultMinElements() {
		return useDefaultMinElements;
	}



	/**
	 * @param useDefaultMinElements the useDefaultMinElements to set
	 */
	public void setUseDefaultMinElements(boolean useDefaultMinElements) {
		this.useDefaultMinElements = useDefaultMinElements;
	}


	/**
	 * @param useDefaultMaxElements the useDefaultMaxElements to set
	 */
	public void setUseDefaultMaxElements(boolean useDefaultMaxElements) {
		this.useDefaultMaxElements = useDefaultMaxElements;
	}


	/**
	 * @return the useDefaultMaxElements
	 */
	public boolean isUseDefaultMaxElements() {
		return useDefaultMaxElements;
	}

	public int getKeyFieldsNumber(){
		if (null == key){
			return 0;
		}
		return key.getFieldsNumber();
	}

	/**
	 * @return the keys
	 */
	public Field getKey() {
		return key;
	}
	

	/**
	 * @param keysEx the keysEx to set
	 */
	public void setKey(Field key) {
		this.key = key;
	}
	public boolean addKeyField(String key){
		if (null == key){
			return false;
		}
		if (null == this.key){
			this.key = new Field(key);
		}
		else {
			this.key.addField(key);
		}
		return true;
	}
	public String getKeyField(int index){
		if (null == this.key){
			return null;
		}
		return this.key.getField(index);
		
		
	}
	
	public String removeKeyField(String key){
		if (null == this.key){
			return null;
		}
		return this.key.removeField(key);
		
		
	}
	public String removeKeyField(int index){
		if (null == this.key){
			return null; 
		}
		return this.key.removeField(index);
	}
	public boolean isKeyNode(String nodeName){
		if (null == nodeName){
			return false;
		}
		return this.key.hasField(nodeName);
	}
	

	public Node getKeyNode(int index){
		String nodeName = getKeyField(index);
		if (null == nodeName){
			return null;
		}
		
		return getSchemaSon(nodeName);
	}
	public Node getKeyNode(String nodeName){
		if (null == nodeName){
			return null;
		}
		
		if (!isKeyNode(nodeName)){
			return null;
		}
		
		return getSchemaSon(nodeName);
		
	}
	/**
	 * ��ȡunique����Ŀ
	 * @return
	 * @see com.netscenery.model.Unique
	 */
	public int getUniquesNumber(){
		if (null == this.uniques){
			return 0;
		}
		return this.uniques.size();
	}
	/**
	 * ���ָ������ƴ���Unique
	 * @param name
	 * @return
	 * @see com.netscenery.model.Unique
	 */
	public Unique createUnique(String unique){
		if (null == unique){
			return null;
		}
		
		return new Unique(this,unique);
	}
	/**
	 * ���һ��Unique
	 * @param n
	 * @return
	 * @see com.netscenery.model.Unique
	 */
	public boolean addUnique(Unique n){
		if(null == n){
			return false;
		}
		
		if (null == this.uniques){
			this.uniques = new ArrayList<Unique>(1);
		}
		if (null != this.getUnique(n.toString())){
			return false;
		}
		return this.uniques.add(n);
		

	}
	/**
	 * �����Ż�ȡUnique
	 * @param index
	 * @return
	 * @see com.netscenery.model.Unique
	 */
	public Unique getUnique(int index){
		if (null == this.uniques){
			return null;
		}
		if (index >= this.uniques.size()){
			return null;
		}
		return this.uniques.get(index);
	}
	/**
	 * �����ƻ�ȡUnique
	 * @param name
	 * @return
	 * @see com.netscenery.model.Unique
	 */
	public Unique getUnique(String unique){
		if (null == this.uniques){
			return null;
		}
		int size = uniques.size();
		if (size <= 0){
			return null;
		}
		
		for (int i = 0; i < size; i++){
			Unique n = this.uniques.get(i);
			if (null != n){
				if (n.toString().equals(unique)){
					return n;
				}
			}
		}
		return null;
	}
	/**
	 * ������ɾ��Unique
	 * @param index
	 * @return Unique
	 * @see com.netscenery.model.Unique
	 */
	public Unique removeUnique(int index){
		if (null == this.uniques){
			return null;
		}
		if (index >= this.uniques.size()){
			return null;
		}
		return this.uniques.remove(index);
	}
	/**
	 * ������ɾ��Unique
	 * @param name
	 * @return Unique
	 * @see com.netscenery.model.Unique
	 */
	public Unique removeUnique(String unique){
		if (null == this.uniques){
			return null;
		}
		int size = uniques.size();
		if (size <= 0){
			return null;
		}
		
		
		for (int i = 0; i < size; i++){
			Unique n = this.uniques.get(i);
			if (null != n){
				if (n.toString().equals(unique)){
					return uniques.remove(i);
				}
			}
		}
		return null;
	}
	/**
	 * @return the minElements
	 */
	public int getMinElements() {
		return minElements;
	}
	/**
	 * @param minElements the minElements to set
	 */
	public void setMinElements(int minElements) {
		this.minElements = minElements;
		this.useDefaultMinElements = false;
	}
	/**
	 * @return the maxElements
	 */
	public int getMaxElements() {
		return maxElements;
	}
	/**
	 * @param maxElements the maxElements to set
	 */
	public void setMaxElements(int maxElements) {
		this.maxElements = maxElements;
		this.useDefaultMaxElements = false;
	}

	

	public Validator addSon(Node node){
		return addSon(node,true);
	}
	public Validator addSon(Node node, boolean isNeedCheck){
		Validator validator = new Validator();
		if (null == node){
			validator.setIsValid(false);
			validator.addMsg(new Message(this,ErrTag.ERROR,ErrorCode.COMMON_ERROR));
			return validator;
		}
		Validator sValidator = super.addSon(node,isNeedCheck);
		validator.copy(sValidator);
		return validator;	
	}
	/* (non-Javadoc)
	 * @see com.netscenery.yang.model.Node#validate()
	 */
	@Override
	public Validator validate() {
		Validator validator = new Validator();
		if (getSonsNumber() < 1){
			validator.setIsValid(false);
			validator.addMsg(new Message(this, ErrTag.ERROR,"list must have at least one son node."));
		}
		if (null == key){
			validator.setIsValid(false);
			validator.addMsg(new Message(this, ErrTag.ERROR,"list must have one key."));
		}
		else {
			
			//key must be son node
			int keysize = getKeyFieldsNumber();
			for (int i = 0; i < keysize; i++){
				String keyField = getKeyField(i);
				if (null == keyField){
					continue;
				}
				Node keyNode = getKeyNode(i);
				if (null == keyNode){
					validator.setIsValid(false);
					validator.addMsg(new Message(this, ErrTag.ERROR,"key field:"+ keyField +" has no corresponding node."));
				}
				if (!(keyNode instanceof Leaf)){
					validator.setIsValid(false);
					validator.addMsg(new Message(this, ErrTag.ERROR,"key must be son node with type leaf."));
				}
				
			}
		}
				
		int uniquesize = getUniquesNumber();
		//unique must be leaf node and must be the list's descendant node
		
		for (int i = 0; i < uniquesize; i++){
			Unique unique = getUnique(i);
			if (null == unique){
				continue;
			}
			int uniqueFieldSize = unique.getFieldsNumber();
			for (int j = 0; j< uniqueFieldSize;j++){
				String field = unique.getField(j);
				if (null == field){
					continue;
				}
				
				Node uniNode = unique.getUniqueNode(j);
				if (null == uniNode){
					validator.setIsValid(false);
					validator.addMsg(new Message(this, ErrTag.ERROR,"unique node:"+ field + " have no corresponding node."));
				}
				if (!(uniNode instanceof Leaf)){
					validator.setIsValid(false);
					validator.addMsg(new Message(this, ErrTag.ERROR,"unique node must be descent node with type leaf."));
				}
			}
			
			
		}	
		
		if (!useDefaultMinElements
				&& !useDefaultMaxElements){
			if (minElements > maxElements){
				validator.setIsValid(false);
				validator.addMsg(new Message(this,ErrTag.ERROR,"min-elements is greater than max-elements."));
			}
		}
		
		Validator sValidator = super.validate();
		validator.copy(sValidator);
		return validator;
	}


	@Override
	public void update() {
		// TODO Auto-generated method stub
		
	}
	
	
	
}
